#!/bin/bash
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#

#
# Copyright 2020 Joyent, Inc.
#

#
# This is a wrapper used by jenkins to invoke the different targets needed for
# the Triton platform and SmartOS build variants.
#

if [[ -n "${TRACE}" ]]; then
    export PS4='${BASH_SOURCE}:${LINENO}: '
    set -o xtrace
fi

set -o errexit
set -o pipefail

# Allow users to override the Manta path where we publish artifacts
if [[ -z "${ENGBLD_DEST_OUT_PATH}" ]]; then
    export ENGBLD_DEST_OUT_PATH=/public/builds
fi

export TIMESTAMP=$(TZ=UTC /bin/date "+%Y%m%dT%H%M%SZ")
export BUILDSTAMP=${TIMESTAMP}

# Used to flag if this is a non-default build. This modifies the description
# used for the platform manifest.
export ENGBLD_CUSTOM=''

# Jenkins should set this, otherwise default to the current branch, assuming
# our working directory is a smartos-live repository.
if [[ -z "${BRANCH}" ]]; then
    export BRANCH=$(git branch 2> /dev/null | \
        sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/')
fi

#
# Emit usage information
#
function usage {
    echo "Usage: build_jenkins [options]"
    echo "OPTIONS"
    echo "  -c            remove projects dirs prior to building"
    echo "  -d            build a debug platform"
    echo "  -F <flavor>   build one of the following build flavors:"
    echo "                    triton (default)    a normal platform build"
    echo "                    smartos             only smartos platform bits"
    echo "                    triton-and-smartos  both of the above"
    echo "                    strap-cache         build the strap cache tarball"
    echo "                    ctftools            build the ctftools tarball"
    echo "                    check               do a 'make check' only"
    echo "  -S <stage>    the Jenkins stage name, used to distinguish artifacts"
    echo ""
    echo "ENVIRONMENT"
    echo "  BRANCH                the branch of smartos-live being built"
    echo "  ENGBLD_DEST_OUT_PATH  the Manta path used when uploading artifacts"
    echo "  PLAT_CONFIGURE_ARGS   additional arguments to pass to 'configure'"
    echo "  PLATFORM_BUILD_FLAVOR one of the -F arguments, as above"
    echo "  CONFIGURE_PROJECTS    content for the 'configure-projects' file"
    echo ""
    echo "NOTE"
    echo "  Production builds expect we're building in a freshly cloned"
    echo "  repository. We do not attempt to 'make clean' before rebuilding."
    exit 2
}

#
# A simple log wrapper for running a major build step
#
function log_cmd {
    echo "==== Running $@ ====" | tee -a ${ENGBLD_LOG}
    $@ 2>&1 | tee -a ${ENGBLD_LOG}
}

#
# A simple log wrapper
#
function log {
    $@ 2>&1 | tee -a ${ENGBLD_LOG}
}

#
# Write the Jenkins build artifacts (log files, etc.) to an output
# directory named after the current Jenkins stage name in order to
# disambiguate the artifacts by stage name. gitstatus.json and the
# generated changelog shouldn't change across stages, but let's err
# on the side of caution.
#
function archive_artifacts {
    # Do our best to save all artifacts
    set +o errexit
    if [[ -n "$JENKINS_STAGE_NAME" ]]; then
        echo "Writing Jenkins artifacts to output/$JENKINS_STAGE_NAME"
        mkdir -p output/$JENKINS_STAGE_NAME
        # move these logs because they're large
        mv projects/illumos/log/log.* output/$JENKINS_STAGE_NAME
        cp log/* output/$JENKINS_STAGE_NAME
        for file in output/bits/artifacts.txt \
                output/gitstatus.json \
                output/changelog.txt; do
            cp $file output/$JENKINS_STAGE_NAME
        done
    fi
    set -o errexit
}

#
# Install a trap handler to archive_artifacts so that it gets called regardless
# of errexit or pipefail.
#
trap archive_artifacts EXIT

#
# Main
#
while getopts "cdhF:S:" opt; do
    case "${opt}" in
        c)
            CLEAN_PROJECTS_DIR=true
            ;;
        d)
            # build debug platform bits
            ENGBLD_CONFIGURE_DEBUG_ARG='-d'
            ENGBLD_DEBUG_SUFFIX='-debug'
            ;;
        F)
            PLATFORM_BUILD_FLAVOR="${OPTARG}"
            ;;
        S)
            JENKINS_STAGE_NAME="${OPTARG}"
            ;;
        h)
            usage
            ;;
        *)
            echo "Error: Unknown argument ${opt}"
            usage
    esac
done
shift $((OPTIND - 1))

if [[ -z "$PLATFORM_BUILD_FLAVOR" ]]; then
    PLATFORM_BUILD_FLAVOR="triton"
fi

case "${PLATFORM_BUILD_FLAVOR}" in
    'triton'|'smartos'|'triton-and-smartos'|'strap-cache'|'ctftools'|'check')
        ;;
    *)
        echo "Error: unknown platform build flavor: ${PLATFORM_BUILD_FLAVOR}"
        usage
esac

ENGBLD_LOGDIR=output/bits/platform${ENGBLD_DEBUG_SUFFIX}
ENGBLD_LOG=${ENGBLD_LOGDIR}/build.log

# Rotate our output directories, mostly for the benefit of non-production builds
# We can't log these commands as we're physically removing the log location.
for output in output output-iso output-usb output-vmware; do
    if [[ -d "${output}" ]]; then
        echo "Removing old ${output} directory"
        rm -rf ${output}.old
        echo "Renaming output to ${output}.old"
        mv ${output} ${output}.old
    fi
done

mkdir -p ${ENGBLD_LOGDIR}
touch ${ENGBLD_LOG}

#
# The Jenkins GitHub Pull Request Builder plugin overrides the git
# 'remote.origin.fetch' config setting, along the lines of
# "git config --add remote.origin.fetch +refs/heads/prr-OS-8046:refs/remotes/origin/prr-OS-8046"
# which will break the 'tools/build_changelog' script as we won't have an
# accurate list of the 'release-*' branches when building PRs.
# Reset that now to something sane, and force a fetch.
# This will not modify which branch is currently checked out.
#
git config --replace-all remote.origin.fetch '+refs/heads/*:refs/remotes/origin/*'
git remote update

# Remove any old logs so that these don't get swept up as Jenkins artifacts
log rm -rf log projects/illumos/log

# Is this a release branch build
if echo "${BRANCH}" | grep -q "^release"; then
    ENGBLD_RELEASE=true
else
    ENGBLD_RELEASE=""
fi

#
# ${CONFIGURE_PROJECTS} is multi-line jenkins parameter, set so that users can
# specify which branches of the repositories in the smartos-live 'projects'
# framework to build, and from where they should be cloned. For release builds,
# override all repositories.
#
if [[ -n "${ENGBLD_RELEASE}" ]]; then
    echo "Doing release build - setting configure projects to:"
    sed -e "s/ master: / ${BRANCH}: /g" default.configure-projects > configure-projects
    cat configure-projects
elif [[ -z "${CONFIGURE_PROJECTS}" ]]; then
    echo "Using default configure-projects"
else
    echo "${CONFIGURE_PROJECTS}" > configure-projects
fi

# this can be set to " " to avoid a full strap rebuild for dev purposes
FORCE_STRAP_REBUILD_ARG=${FORCE_STRAP_REBUILD_ARG:--r}

if [[ -n "${CLEAN_PROJECTS_DIR}" ]]; then
    echo "Removing potentially stale projects dirs"
    for proj in $(cat configure-projects | awk -F: '{print $1}'); do
        log_cmd rm -rf projects/$proj
    done
fi

# Configure the build based on the arguments we've gathered
log_cmd  ./configure ${FORCE_STRAP_REBUILD_ARG} \
    ${ENGBLD_CONFIGURE_DEBUG_ARG} \
    ${PLAT_CONFIGURE_ARGS}

case "${PLATFORM_BUILD_FLAVOR}" in
    'triton')
        log_cmd gmake common-release
        log_cmd gmake triton-release
        ;;
    'smartos')
        log_cmd gmake common-release
        log_cmd gmake smartos-only-release
        ;;
    'triton-and-smartos')
        log_cmd gmake common-release
        log_cmd gmake triton-smartos-release
        ;;
    'strap-cache')
        log_cmd gmake strap-cache-release
        ;;
    'ctftools')
        log_cmd gmake ctftools-release
        ;;
    'check')
        log_cmd gmake check
        ;;
esac

#
# Upload artifacts separately for smartos to ~~/public/SmartOS, only if this is
# a non-debug, release build.
# We check for an empty $PLATFORM_DEBUG_SUFFIX as that gets used as the way to
# prevent downstream Jenkins builds (e.g. 'platform-gcc4') uploading artifacts
# to the 'platform' Manta directory, even though they may not strictly be debug
# builds.
#
if [[ -n "${ENGBLD_RELEASE}" && \
        -z "${ENGBLD_CONFIGURE_DEBUG_ARG}" && \
        -z "${PLATFORM_DEBUG_SUFFIX}" ]]; then
    case "${PLATFORM_BUILD_FLAVOR}" in
        'smartos'|'triton-and-smartos')
            log_cmd env TRACE=1 ./tools/smartos-release \
                "${BRANCH}" "${TIMESTAMP}"
            ;;
    esac
fi
